#include "elslider.h"
#include <QApplication>
#include <QPaintEvent>
#include <QPainter>
#include <QPropertyAnimation>
#include <QtMath>
#include "../basic/eltheme.h"
#include "../others/eltooltip.h"

ElSlider::ElSlider(QWidget *parent)
    : ElComponent{parent}
{
    resize(200, 70);
    setCursor(Qt::PointingHandCursor);
    sliderCircle = new ElSliderCircle(this);
    setValue(5);
    initPalette();
}

int ElSlider::min() const
{
    return _min;
}

void ElSlider::setMin(int min)
{
    if (_min == min)
        return;
    _min = min;
}

int ElSlider::max() const
{
    return _max;
}

void ElSlider::setMax(int max)
{
    if (_max == max)
        return;
    _max = max;
}

int ElSlider::scope() const
{
    return qAbs(max() - min());
}

void ElSlider::setScope(int min, int max)
{
    if (min < max) {
        setMax(max);
        setMin(min);
    }
    else {
        setMax(min);
        setMin(max);
    }
}

int ElSlider::value() const
{
    return _value;
}

void ElSlider::setValue(int value)
{
    if (_value == value || value < _min || value > _max)
    {
        return;
    }

    _value = value;
    emit valueChanged(_value);
    _ratio = ((qreal(_value) - min()) / qreal(scope()));
    update();
    sliderCircle->updateTooltip(_value);
}

void ElSlider::setRatio(qreal ratio)
{
    if (ratio > 1)
    {
        ratio = 1;
    }
    else if (ratio < 0)
    {
        ratio = 0;
    }
    _ratio = ratio;

    auto value = qRound(min() + scope() * ratio);
    _value = value;
    emit valueChanged(_value);
    sliderCircle->updateTooltip(_value);
    sliderCircle->setToolTip(QString::number(_value));
    if (_stepStop)
    {
        _ratio = ((qreal(_value) - min()) / qreal(scope()));
    }
    update();
}

void ElSlider::setTooltip(ElTooltip *tooltip)
{
    sliderCircle->setTooltip(tooltip);
    tooltip->setTarget(sliderCircle);
}

ElTooltip *ElSlider::tooltip() const
{
    return sliderCircle->tooltip();
}

bool ElSlider::event(QEvent *e)
{
    if (e->type() == QEvent::EnabledChange) {
        sliderCircle->setEnabled(isEnabled());
        _palette.toggleColorGroup(isEnabled() ? ElPalette::Normal : ElPalette::Disabled);
        update();
    }
    return ElComponent::event(e);
}

void ElSlider::paintEvent(QPaintEvent *e)
{
    QPainter painter(this);
    painter.setBrush(_palette.color(ElPalette::Background));
    painter.setPen(QColor(228, 231, 237));
    qreal y = getDrawRect().center().y() - _sliderheight / 2;
    qreal x = sliderWidthScope().first - _sliderheight / 2;
    auto slider_rect = QRectF(x, y, sliderWidth(), _sliderheight);
    painter.drawRoundedRect(slider_rect, _sliderheight / 2, _sliderheight / 2);


    auto r = sliderCircle->rect();
    qreal progress = x + _ratio * sliderWidth();
    r.moveCenter(QPoint(progress, getDrawRect().center().y()));
    sliderCircle->move(r.topLeft());

    painter.setBrush(_palette.color(ElPalette::Foreground));
    painter.drawRoundedRect(x,
                            y,
                            _ratio * sliderWidth(),
                            _sliderheight,
                            _sliderheight / 2,
                            _sliderheight / 2);
    e->accept();
}

void ElSlider::mousePressEvent(QMouseEvent *e)
{
    if (!isEnabled()) {
        e->ignore();
        return;
    }

    setRatio((e->position().x() - sliderWidthScope().first) / sliderWidth());
    emit sliderPressed();
    e->accept();
}

void ElSlider::initPalette()
{
    _palette.setColor(ElPalette::Background, QColor(228, 231, 237));
    _palette.setColor(ElPalette::Foreground, ThemeColor::primaryColor);
    _palette.setColor(ElPalette::Disabled, ElPalette::Background, QColor(192, 196, 204));
    _palette.setColor(ElPalette::Disabled, ElPalette::Foreground, QColor(192, 196, 204));
}

ElSlider::ElSliderCircle::ElSliderCircle(ElSlider *parent)
    : ElComponent{parent}
{
    resize(3 * maxRadius(), 3 * maxRadius());
    _slider = parent;
    setAttribute(Qt::WA_Hover);
    setCursor(Qt::OpenHandCursor);
    _animation = new QPropertyAnimation(this, "geometry", this);
    _animation->setDuration(1200);
    _animation->setEasingCurve(QEasingCurve::OutQuad);

    auto tooltip = new ElTooltip(this);
    tooltip->setPlacement(ElTooltip::Top);
    setTooltip(tooltip);
    initPalette();
}

qreal ElSlider::ElSliderCircle::maxRadius() const
{
    return _radius + 1;
}

qreal ElSlider::sliderWidth() const
{
    auto [xMin, xMax] = sliderWidthScope();
    return xMax - xMin;
}

bool ElSlider::stepStop() const
{
    return _stepStop;
}

void ElSlider::setStepStop(bool newStepStop)
{
    _stepStop = newStepStop;
}

QPair<qreal, qreal> ElSlider::sliderWidthScope() const
{
    return {getDrawRect().x() + sliderCircle->size().width() / 2,
            getDrawRect().x() + getDrawRect().width() - sliderCircle->size().width() / 2};
}

void ElSlider::ElSliderCircle::updateTooltip(int value)
{
    _tooltip->setContent(QString::number(value));
    _tooltip->update();
}

bool ElSlider::ElSliderCircle::event(QEvent *e)
{
    if (e->type() == QEvent::EnabledChange) {
        _palette.toggleColorGroup(isEnabled() ? ElPalette::Normal : ElPalette::Disabled);
        update();
    }
    return ElComponent::event(e);
}

void ElSlider::ElSliderCircle::paintEvent(QPaintEvent *e)
{
    QPainter painter(this);
    painter.setBrush(Qt::white);
    QPen pen;
    pen.setCapStyle(Qt::RoundCap);
    pen.setJoinStyle(Qt::RoundJoin);
    pen.setWidthF(1.5);
    pen.setColor(_palette.color(ElPalette::Border));
    painter.setPen(pen);

    auto curR = _isHover ? maxRadius() : radius();
    painter.drawEllipse(getDrawRect().center(), curR, curR);

    e->accept();
}

void ElSlider::ElSliderCircle::enterEvent(QEnterEvent *e)
{
    if (!isEnabled()) {
        e->ignore();
        return;
    }
    showTooltip();
    _isHover = true;

    e->accept();
}

void ElSlider::ElSliderCircle::leaveEvent(QEvent *e)
{
    if (!isEnabled()) {
        e->ignore();
        return;
    }
    hideTooltip();
    _isHover = false;
    e->accept();
}

void ElSlider::ElSliderCircle::mousePressEvent(QMouseEvent *e)
{
    if (!isEnabled()) {
        e->ignore();
        return;
    }
    setCursor(Qt::ClosedHandCursor);
    emit _slider->sliderPressed();
    e->accept();
}

void ElSlider::ElSliderCircle::mouseReleaseEvent(QMouseEvent *e)
{
    if (!isEnabled()) {
        e->ignore();
        return;
    }
    setCursor(Qt::OpenHandCursor);
    emit _slider->sliderReleased();
    e->accept();
}

void ElSlider::ElSliderCircle::mouseMoveEvent(QMouseEvent *e)
{
    if (!isEnabled()) {
        e->ignore();
        return;
    }
    auto pos = mapToParent(e->position());
    auto [xMin, xMax] = _slider->sliderWidthScope();
    if (pos.x() < xMin)
    {
        _slider->setRatio(0.0);
        e->ignore();
        return;
    }
    else if(pos.x() > xMax) {
        _slider->setRatio(1.0);
        e->ignore();
        return;
    }
    else {
        qreal radio = (pos.x() - xMin) / _slider->sliderWidth();
        _slider->setRatio(radio);
    }

    emit _slider->sliderMoved();
    e->accept();
}

void ElSlider::ElSliderCircle::initPalette()
{
    _palette.setColor(ElPalette::Border, ThemeColor::primaryColor);
    _palette.setColor(ElPalette::Disabled, ElPalette::Border, QColor(192, 196, 204));
}


qreal ElSlider::ElSliderCircle::radius() const
{
    return _radius;
}

void ElSlider::ElSliderCircle::setRadius(qreal radius)
{
    if (qFuzzyCompare(_radius, radius))
        return;
    _radius = radius;
    update();
}
